﻿using Controller.Enum;
using Controller.Model;
using Controller.Utils;
using ControllerManageServer.Controller.Prada;
using ControllerManageServer.Handler;
using Leeder.Logger;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ControllerManageServer.Controller
{
    /// <summary>
    /// 控制器
    /// </summary>
    abstract class SocketServerBaseController : IController
    {
        #region 变量声明

        /// <summary>
        /// 空闲间隔时间
        /// </summary>
        public int IdleIntervalTime { get; set; } = 30;
        /// <summary>
        /// 发送间隔时间
        /// </summary>
        public int SendIntervalTime { get; set; } = 20;
        /// <summary>
        /// 重新发送的次数,默认是-1
        /// </summary>
        public int ReSendCount { get; set; } = -1;
        /// <summary>
        /// 日志对象
        /// </summary>
        protected LogOperate logObj;
        /// <summary>
        /// ip地址
        /// </summary>
        protected string ipAddress;
        /// <summary>
        /// 端口号
        /// </summary>
        protected int port;
        /// <summary>
        /// 是否停止
        /// </summary>
        private bool isStop;
        /// <summary>
        /// 发送数据队列
        /// </summary>
        private ConcurrentQueue<byte[]> sendDataQueue;
        /// <summary>
        /// 发送数据线程
        /// </summary>
        private Thread sendDataThread;
        /// <summary>
        /// 字符编码,默认是ASCII码
        /// </summary>
        public Encoding DefaultEncoding = Encoding.ASCII;
        /// <summary>
        /// 爱鸥的Socket处理
        /// </summary>
        protected SocketClientHandler Controller;
        /// <summary>
        /// 控制器类型
        /// </summary>
        private EquipmentBrandEnum ControllerType;
        /// <summary>
        /// 上次发送到控制器的时间
        /// </summary>
        private DateTime lastSendToControler;

        #endregion 变量声明

        #region 事件定义

        /// <summary>
        /// 数据接收事件,key:应该回给哪个客户端的socket的key(ip:port),返回的数据模型
        /// </summary>
        public event Action<string, ServerPacketModel> OnDataReceive;

        #endregion 事件定义

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iIp">ip地址</param>
        /// <param name="iPort">端口号</param>
        /// <param name="iControllerType">控制器类型</param>
        public SocketServerBaseController(string iIp, int iPort, EquipmentBrandEnum iControllerType = EquipmentBrandEnum.AIOI)
        {
            this.ipAddress = iIp;
            this.port = iPort;
            this.ControllerType = iControllerType;
        }

        /// <summary>
        /// 启动
        /// </summary>
        public virtual void Start()
        {
            logObj = Log.GetLogger(GetType());
            // 初始化
            Init();
            // 处理控制器数据接收
            Controller.OnDataReceiveEvent += ReceiveData;
            Controller.OnConnectionStateChangeEvent += ControllerConnectionStateChange;
            Controller.Start();
            //  发送数据线程
            sendDataThread = new Thread(SendDataFunction) { IsBackground = true };
            sendDataThread.Start();
        }

        /// <summary>
        /// 停止
        /// </summary>
        public virtual void Stop()
        {
            isStop = true;
            if (sendDataThread != null)
            {
                try { sendDataThread.Abort(); } catch { }
                sendDataThread = null;
            }
            Controller.Stop();
            Controller = null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString() {
            return $"{ipAddress}:{port}";
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            isStop = false;
            lastSendToControler = DateTime.Now;
            sendDataQueue = new ConcurrentQueue<byte[]>();
            // 根据不同的控制器类型,去创建对应的通讯控制器
            switch (ControllerType)
            {
                default:
                    Controller = new AioiSocketClientHandler(ipAddress, port);
                    break;
            }
        }

        /// <summary>
        /// 控制器接收到数据的处理
        /// </summary>
        /// <param name="iDatas">接收到的数据</param>
        public abstract void ReceiveData(byte[] iDatas);

        /// <summary>
        /// 控制器连接状态修改
        /// </summary>
        /// <param name="iState"></param>
        protected abstract void ControllerConnectionStateChange(bool iState);

        /// <summary>
        /// 发送数据的线程函数
        /// </summary>
        private void SendDataFunction()
        {
            int count = 0;
            bool state = false;
            byte[] data, temp;
            bool isHeartBeat = false;
            while (!isStop)
            {
                isHeartBeat = false;
                try
                {
                    // 没有可发送的数据,可以多休息一会
                    if (!sendDataQueue.TryDequeue(out data))
                    {
                        //Thread.Sleep(IdleIntervalTime);
                        //continue;
                        if ((DateTime.Now - lastSendToControler).TotalMilliseconds > 1000)
                            data = GetHeartbeat();
                        isHeartBeat = true;
                        if (data == null || data.Length == 0)
                        {
                            Thread.Sleep(IdleIntervalTime);
                            continue;
                        }
                    }
                    // 如果发送失败,那么就重发
                    while (!state && (ReSendCount == -1 || count < ReSendCount))
                    {
                        temp = GenerateSendData(data);
                        
                        logObj.Debug($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} <> [Aoio][{ipAddress}:{port}]发送 --> {ByteUtils.ByteArrayToHexString(temp)}\t{ByteUtils.ByteArrayToAioiAsciiString(temp)}\r\n");
                        
                        state = Controller.SendData(temp);
                        count++;
                        // 发送失败
                        if (!state)
                        {
                            SendFailure(count, temp);
                            Thread.Sleep(5);
                        }
                        else
                        {
                            lastSendToControler = DateTime.Now;
                        }
                    }
                    count = 0;
                    state = false;
                    //if (data[0] == 'D')
                    //{
                    //    Thread.Sleep(300);
                    //}
                    //else {
                        Thread.Sleep(15);
                    //}
                   // Thread.Sleep(SendIntervalTime);
                }
                catch (Exception ex)
                {
                    logObj.Error(ExceptionType.BusinessException, ex);
                }
            }
        }

        /// <summary>
        /// 发送失败
        /// </summary>
        /// <param name="iCount"></param>
        /// <param name="iData"></param>
        public virtual void SendFailure(int iCount, byte[] iData)
        {
            logObj.Error($"{DateTime.Now} <> [Aoio][{ipAddress}:{port}]发送 --> 发送失败! {ByteUtils.ByteArrayToHexString(iData)}\r\n");
        }

        /// <summary>
        /// 生成发送数据
        /// </summary>
        /// <param name="iDatas">指令</param>
        /// <returns></returns>
        public virtual byte[] GenerateSendData(byte[] iDatas)
        {
            return iDatas;
        }

        /// <summary>
        /// 获取心跳数据
        /// </summary>
        /// <returns></returns>
        public virtual byte[] GetHeartbeat() { return null; }

        /// <summary>
        /// 设置发送数据
        /// </summary>
        /// <param name="iDatas">需要发送的数据</param>
        public void SetSendData(byte[] iDatas)
        {
            sendDataQueue.Enqueue(iDatas);
        }

        /// <summary>
        /// 设置发送的数据
        /// </summary>
        /// <param name="key">当前请求在收到回复后的应该发给哪个客户端的凭证</param>
        /// <param name="iPacket">Socket服务收到的数据包</param>
        public abstract void SetSendData(string key, ServerPacketModel iPacket);

        /// <summary>
        /// 数据接收事件
        /// </summary>
        /// <param name="key">从哪来?响应哪个DPS客户端发过来的数据</param>
        /// <param name="iModel">响应数据</param>
        protected void DataReceive(string key, ServerPacketModel iModel)
        {
            OnDataReceive?.BeginInvoke(key, iModel, null, null);
        }

    }
}
